# 与activity相关的序列化器

from rest_framework import serializers

from sa.models import User, Project, Activity

from django.utils import timezone


class ActivitySerializer(serializers.ModelSerializer):
    # 做反序列化输入，使用PrimaryKeyRelatedField，只用输入id
    project = serializers.PrimaryKeyRelatedField(
        queryset=Project.objects.all(), write_only=True,
        help_text="项目ID（仅反序列化输入）"
    )
    creator = serializers.PrimaryKeyRelatedField(
        queryset=User.objects.all(), write_only=True,
        help_text="创建者ID（仅反序列化输入）"
    )
    activity_type_display = serializers.CharField(
        source='get_activity_type',
        read_only=True,
        help_text='工作分类显示'
    )

    # SerializerMethodField是一个只读字段, 它不会从模型中直接获取数据，而是通过调用序列化器中的一个方法来获取数据。
    # 在序列化器中，你可以定义一个或多个 SerializerMethodField 字段，并指定一个方法名（去掉 get_ 前缀）来获取该字段的值。
    project_info = serializers.SerializerMethodField()  # 仅序列化输出
    creator_info = serializers.SerializerMethodField()  # 仅序列化输出

    class Meta:
        model = Activity
        fields = "__all__"
        read_only_fields = [
            'id', 'activity_number',
            'points']

    # DRF 会自动查找名为 get_<field_name> 的方法来获取 SerializerMethodField 的值。
    # 例如，定义了一个名为 project_info 的 SerializerMethodField，DRF 会查找 get_project_info 方法。
    def get_project_info(self, obj):
        try:
            # obj 是当前正在序列化的 activity 对象
            # 当两个或多个模块相互依赖时，延迟导入可以帮助打破循环依赖。
            from sa.serializers.projectSerializer import ProjectInfoSerializer
            # 使用ProjectInfoSerializer这个序列化器类来 序列化 一个具体的对象实例。
            # instance=obj.project      activity对象关联的的project（是一个关联对象）
            # context=self.context    序列化器的上下文（context）
            # 上下文是一个字典，可以用来在序列化器之间传递额外的信息，比如请求对象、视图对象或其他自定义数据。
            serializer = ProjectInfoSerializer(instance=obj.project, context=self.context)
            return serializer.data
        except Exception as e:
            # 处理异常，例如记录日志或返回默认值
            return None  # 或者返回一个默认的字典或错误信息

    def get_creator_info(self, obj):
        try:
            # 当两个或多个模块相互依赖时，延迟导入可以帮助打破循环依赖。
            from sa.serializers.accountSerializer import UserInfoSerializer
            serializer = UserInfoSerializer(instance=obj.creator, context=self.context)
            return serializer.data
        except Exception as e:
            # 处理异常
            return None

    """
    self.context 序列化器的 context 是一个字典，包含视图传递给序列化器的额外数据。
    默认情况下，DRF 会自动传递 request 和 view 到序列化器的 context 中（如果视图继承自 GenericAPIView 或 ModelViewSet）
    在DRF中 self.kwargs 是一个字典，包含了从 URL 路由中捕获的命名参数。
    """

    def validate(self, attrs):
        # 根据上下文自动生成 activity_number
        # 获取当前视图实例
        view = self.context.get('view')
        if not view:
            raise serializers.ValidationError("无法获取视图上下文view")
        # self.kwargs['project_pk'] 从 URL 中获取项目 ID
        # 从视图的 kwargs 中获取 project_pk
        project_pk = view.kwargs.get('project_pk')
        if not project_pk:
            raise serializers.ValidationError('URL 中未提供 project_pk。')
        try:
            project_obj = Project.objects.get(id=project_pk)
        except Project.DoesNotExist:
            raise serializers.ValidationError(f"项目 ID {project_pk} 不存在。")

        # 使用 self.context.get('request').method 检查当前请求是 POST、PUT 还是 PATCH。
        # 或者
        # request = self.context.get('request')
        # if request.method == 'POST' and 'activity_number' not in attrs:
        # 只有新增 post 时，才自动生成 activity_number，更新时 activity_number 保持不变
        request_method = self.context.get('request').method
        if request_method == 'POST' and 'activity_number' not in attrs:
            try:
                # 获取当前项目最后一个 activity。
                last_activity = project_obj.activity_set.all().order_by('-id').first()
                # 初始化新编号
                new_number = 1
                if last_activity:
                    last_activity_number = last_activity.activity_number
                    # 提取子编号
                    try:
                        # 以 . 为分隔符拆分成一个列表,取下标是1的字符串
                        sub_number = int(last_activity_number.split('.')[1])
                        new_number = sub_number + 1
                    except Exception as e:
                        new_number = 1
                if not hasattr(project_obj, 'SR_No') or not project_obj.SR_No:
                    raise serializers.ValidationError("项目缺少SR编号(SR_No)，无法生成活动编号")
                activity_number = f"{project_obj.SR_No}.{new_number}"
                attrs['activity_number'] = activity_number
            except Project.DoesNotExist:
                raise serializers.ValidationError(f"项目 ID {project_pk} 不存在。")

        # 验证activity_date
        activity_date = attrs.get('activity_date')
        if activity_date < project_obj.start_date:
            raise serializers.ValidationError({
                'activity_date': 'activity日期不能早于项目开始日期。'
            })
        if activity_date > timezone.now().date():
            raise serializers.ValidationError({
                'activity_date': 'activity日期不能晚于当前日期。'
            })
        attrs['activity_date'] = activity_date

        # 验证开始和结束时间
        start_time = attrs.get('start_time')
        if not start_time:
            raise serializers.ValidationError({
                'start_time': '开始时间不能为空'
            })
        attrs['start_time'] = start_time
        end_time = attrs.get('end_time')
        if not end_time:
            raise serializers.ValidationError({
                'end_time': '结束时间不能为空'
            })
        attrs['end_time'] = end_time

        # 验证加班时间，如果存在
        is_overtime = attrs.get('is_overtime')
        total_time = attrs.get('total_time', 0)
        overtime = attrs.get('overtime', 0)
        if is_overtime and overtime <= 0:
            raise serializers.ValidationError({
                'overtime': '加班时间不能是0。'
            })
        if overtime != 0 and overtime > total_time:
            raise serializers.ValidationError({
                'overtime': '加班时间不能超过工作总时间。'
            })
        attrs['overtime'] = overtime

        return attrs